package com.ficus.road.maintain.handler.monitor;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ficus.road.maintain.core.model.Confirmation;
import com.ficus.road.maintain.core.model.Hit;
import com.ficus.road.maintain.core.model.OperationLog;
import com.ficus.road.maintain.dao.HitDao;
import com.ficus.road.maintain.dao.OperationLogDao;
import com.ficus.road.maintain.dto.Checklist;
import com.ficus.road.maintain.dto.ChecklistOfCar;
import com.ficus.road.maintain.util.FormatUtil;
import com.ficus.road.maintain.util.MyDateUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author xiawen yang
 * @date 2022/5/23 下午7:13
 */
@Order(2)
@RequiredArgsConstructor
@Component
@Slf4j
public class BusinessMonitorHandler extends AbstractMonitorHandler {

    private final HitDao hitDao;
    private final OperationLogDao operationLogDao;
    @Value("${monitor.recount}")
    private boolean recount;

    @Override
    Checklist doFilter(Checklist fetch) {
        log.info("业务监测统计开始");
        long start = System.currentTimeMillis();
        Date date = new Date();
        String yesterdayDateStr = MyDateUtil.dateFormatStr(DateUtils.addDays(date, -1), "yyyy-MM-dd");
        List<ChecklistOfCar> carCheckList = fetch.getCarList();

        Date startOfDay = MyDateUtil.getStartOfDay(date);
        //病害merge数统计
        Query mergeQuery = new Query(Criteria.where("list.1").exists(true).and("list").elemMatch(Criteria.where("hit_time").gte(startOfDay.getTime() / 1000)));
        List<Hit> mergeQueryHits = hitDao.findByQuery(mergeQuery);
        Map<String, List<Hit>> mergeHitsMap = mergeQueryHits.stream().collect(Collectors.groupingBy(hit -> hit.getAttrs().getCarId()));
        //当日病害数统计
        Query query = new Query(Criteria.where("first_hit_time").gte(startOfDay.getTime() / 1000).and("attrs.confirmation.status").nin(Confirmation.ConfirmationStatus.DELETE));
        List<Hit> hits = hitDao.findByQuery(query);
        Map<String, List<Hit>> newHitsMap = hits.stream().collect(Collectors.groupingBy(i -> i.getAttrs().getCarId()));
        //推送中海数（成功数）
        Query pushQuery = new Query(Criteria.where("title").is("推送中海").and("type").is("info").and("operate_date").gte(MyDateUtil.getStartOfDay(new Date())));
        List<OperationLog> pushList = operationLogDao.findByQuery(pushQuery);
        //总病害数统计
        Checklist yesterdayFetch = checklistDao.fetch(yesterdayDateStr);
        List<ChecklistOfCar> yesterdayCarList = null;
        if (ObjectUtils.isNotEmpty(yesterdayFetch)) {
            yesterdayCarList = yesterdayFetch.getCarList();
        }
        List<ChecklistOfCar> yCarList = yesterdayCarList;
        carCheckList.stream().forEach(checklistOfCar -> {
            //merge病害数统计
            List<Hit> mergeHitsList = mergeHitsMap.get(checklistOfCar.getCarId());
            if (ObjectUtils.isNotEmpty(mergeHitsList)) {
                checklistOfCar.setMergeNum((long) mergeHitsList.size());
            }
            //当日病害数统计
            List<Hit> newHitsList = newHitsMap.get(checklistOfCar.getCarId());
            long hitNum = 0;
            long passNum = 0;
            if (ObjectUtils.isNotEmpty(newHitsList)) {
                hitNum = newHitsList.size();
                long uncheckHitNum = newHitsList.stream().filter(hit -> hit.getAttrs().getConfirmation().getStatus().equals(Confirmation.ConfirmationStatus.TO_BE_CONFIRMED)).count();
                passNum = newHitsList.stream().filter(hit -> hit.getAttrs().getConfirmation().getStatus().equals(Confirmation.ConfirmationStatus.CORRECT)).count();
                double dHitNum = (double) hitNum;
                double dUncheckHitNum = (double) uncheckHitNum;
                double dPassNum = (double) passNum;
                //发现新病害数(包括标注的)
                checklistOfCar.setHitNum(hitNum);
                //未审核数
                checklistOfCar.setUncheckHitNum(uncheckHitNum);
                //审核率
                checklistOfCar.setCheckRate(hitNum == 0 ? 0 : FormatUtil.keepDecimalsOfK((dHitNum - dUncheckHitNum) / dHitNum, 2));
                //审核通过数
                checklistOfCar.setPassHitNum(passNum);
                //通过率(包括标注的病害)
                checklistOfCar.setPassRate(hitNum == 0 ? 0 : FormatUtil.keepDecimalsOfK(dPassNum / dHitNum, 2));
            }
            //推送中海数统计
            if (ObjectUtils.isNotEmpty(pushList)) {
                long pushCount = pushList.stream().filter(operationLog -> {
                    JSONArray jsonArray = JSONArray.parseArray(operationLog.getParams());
                    for (int i = 0; i < jsonArray.size(); i++) {
                        JSONObject jsonObject = jsonArray.getJSONObject(i);
                        if (ObjectUtils.isNotEmpty(jsonObject)) {
                            JSONObject iddr = jsonObject.getJSONObject("iddr");
                            if (ObjectUtils.isNotEmpty(iddr)) {
                                JSONObject info = iddr.getJSONObject("info");
                                if (ObjectUtils.isNotEmpty(info)) {
                                    String carId = info.getString("devid");
                                    if (checklistOfCar.getCarId().equals(carId)) {
                                        return true;
                                    }
                                }
                            }
                        }
                    }
                    return false;
                }).count();
                checklistOfCar.setPushThirdNum(pushCount);
            }
            long yTotalYHitNum = 0, yTotalYPassHitNum = 0;
            if (recount) {
                //统计当日之前的总病害
                Query totalHitQuery = new Query(Criteria.where("first_hit_time").lte(startOfDay.getTime() / 1000).and("attrs.confirmation.status").nin(Confirmation.ConfirmationStatus.DELETE).and("attrs.car_id").is(checklistOfCar.getCarId()));
                yTotalYHitNum = hitDao.count(totalHitQuery);
                Query totalPassQuery = new Query(Criteria.where("first_hit_time").lte(startOfDay.getTime() / 1000).and("attrs.confirmation.status").is(Confirmation.ConfirmationStatus.CORRECT).and("attrs.car_id").is(checklistOfCar.getCarId()));
                yTotalYPassHitNum = hitDao.count(totalPassQuery);
            } else {
                ChecklistOfCar yesterdayData = yCarList.stream().filter(yChecklistOfCar -> yChecklistOfCar.getCarId().equals(checklistOfCar.getCarId())).findFirst().get();
                yTotalYHitNum = yesterdayData.getTotalNewHitNum();
                yTotalYPassHitNum = yesterdayData.getTotalPassHitNum();
            }
            //总病害数
            checklistOfCar.setTotalNewHitNum(yTotalYHitNum + hitNum);
            //总审核通过数
            checklistOfCar.setTotalPassHitNum(yTotalYPassHitNum + passNum);
        });
        checklistDao.saveOrUpdate(fetch);
        log.info("业务监测统计耗时： {} ms", System.currentTimeMillis() - start);
        return fetch;
    }
}
